home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1996 #15 / Monster Media Number 15 (Monster Media)(July 1996).ISO / bbs_util / bsrc_260.zip / SRC.ZIP / MAILOVLY.C < prev    next >
C/C++ Source or Header  |  1996-02-20  |  31KB  |  1,385 lines

  1. /*--------------------------------------------------------------------------*/
  2. /*                                                                          */
  3. /*                                                                          */
  4. /*      ------------         Bit-Bucket Software, Co.                       */
  5. /*      \ 10001101 /         Writers and Distributors of                    */
  6. /*       \ 011110 /          Freely Available<tm> Software.                 */
  7. /*        \ 1011 /                                                          */
  8. /*         ------                                                           */
  9. /*                                                                          */
  10. /*              (C) Copyright 1987-96, Bit Bucket Software Co.              */
  11. /*                                                                          */
  12. /*                 This module was written by Bob Hartman                   */
  13. /*                                                                          */
  14. /*                   BinkleyTerm Mail Control Routines                      */
  15. /*                                                                          */
  16. /*                                                                          */
  17. /*    For complete  details  of the licensing restrictions, please refer    */
  18. /*    to the License  agreement,  which  is published in its entirety in    */
  19. /*    the MAKEFILE and BT.C, and also contained in the file LICENSE.260.    */
  20. /*                                                                          */
  21. /*    USE  OF THIS FILE IS SUBJECT TO THE  RESTRICTIONS CONTAINED IN THE    */
  22. /*    BINKLEYTERM  LICENSING  AGREEMENT.  IF YOU DO NOT FIND THE TEXT OF    */
  23. /*    THIS  AGREEMENT IN ANY OF THE  AFOREMENTIONED FILES,  OR IF YOU DO    */
  24. /*    NOT HAVE THESE FILES,  YOU  SHOULD  IMMEDIATELY CONTACT BIT BUCKET    */
  25. /*    SOFTWARE CO.  AT ONE OF THE  ADDRESSES  LISTED BELOW.  IN NO EVENT    */
  26. /*    SHOULD YOU  PROCEED TO USE THIS FILE  WITHOUT HAVING  ACCEPTED THE    */
  27. /*    TERMS  OF  THE  BINKLEYTERM  LICENSING  AGREEMENT,  OR  SUCH OTHER    */
  28. /*    AGREEMENT AS YOU ARE ABLE TO REACH WITH BIT BUCKET SOFTWARE, CO.      */
  29. /*                                                                          */
  30. /*                                                                          */
  31. /* You can contact Bit Bucket Software Co. at any one of the following      */
  32. /* addresses:                                                               */
  33. /*                                                                          */
  34. /* Bit Bucket Software Co.        FidoNet  1:104/501, 1:343/491             */
  35. /* P.O. Box 460398                AlterNet 7:42/1491                        */
  36. /* Aurora, CO 80046               BBS-Net  86:2030/1                        */
  37. /*                                Internet f491.n343.z1.fidonet.org         */
  38. /*                                                                          */
  39. /* Please feel free to contact us at any time to share your comments about  */
  40. /* our software and/or licensing policies.                                  */
  41. /*                                                                          */
  42. /*--------------------------------------------------------------------------*/
  43.  
  44. /* Include this file before any other includes or defines! */
  45.  
  46. #include "includes.h"
  47.  
  48. static char LOCALFUNC mail_stat (MAILP);
  49. static int LOCALFUNC xmit_install (MAILP, ADDRP);
  50. static MAILP LOCALFUNC xmit_find (MAILP, ADDRP);
  51. static long LOCALFUNC netsize (MAILP);
  52. static int LOCALFUNC any_mail (MAILP);
  53. static void LOCALFUNC do_xmit_line (char *, MAILP);
  54. static void LOCALFUNC xmit_sort (void);
  55. static void LOCALFUNC kill_one (ADDRP address);
  56. static void LOCALFUNC xmit_delete_one (void);
  57. char *mail_status_chars (unsigned int);
  58.  
  59. static char *HoldFmtStr = "%-12.12s %3d %4.4s %5.5s %c";
  60. static char *HoldNoSize = "%-21.21s %5.5s %c";
  61.  
  62. void 
  63. xmit_sameplace ()
  64. {
  65.     MAILP p, p1;
  66.  
  67.     /* Find the guy we just gave mail to */
  68.  
  69.     p = find_mail (&remote_addr);
  70.     remote_addr.Zone = remote_addr.Net = remote_addr.Node = remote_addr.Point = 0;
  71.     remote_addr.Domain = NULL;
  72.     if (p == NULL)
  73.     {
  74.         /* He is not there */
  75.         return;
  76.     }
  77.  
  78.     /* Save our current pointer */
  79.  
  80.     p1 = next_mail;
  81.     if (p != next_mail)
  82.     {
  83.         /* If it is not the one we just gave mail to, save ptr and delete */
  84.         next_mail = p;
  85.         xmit_delete ();
  86.         next_mail = p1;
  87.     }
  88.     else
  89.     {
  90.         /* It was the guy at the head of the list, so just delete him */
  91.         xmit_delete ();
  92.     }
  93.  
  94.     /* If we came in with a null, leave with a null */
  95.  
  96.     if (p1 == NULL)
  97.         next_mail = NULL;
  98.  
  99.     return;
  100. }
  101.  
  102. MAILP 
  103. find_mail (ADDRP address)
  104. {
  105.     MAILP p;
  106.  
  107.     p = mail_top;
  108.     while (p != NULL)
  109.     {
  110.         if ((no_zones || (p->mail_addr.Zone == address->Zone)) &&
  111.             (p->mail_addr.Net == address->Net) &&
  112.             (p->mail_addr.Node == address->Node) &&
  113.             (p->mail_addr.Point == address->Point) &&
  114.             ((p->mail_addr.Domain == address->Domain) ||
  115.                 ((p->mail_addr.Domain == my_addr.Domain) &&
  116.                     (address->Domain == NULL))))
  117.             break;
  118.         p = p->next;
  119.     }
  120.  
  121.     return (p);
  122. }
  123.  
  124. static int LOCALFUNC 
  125. xmit_install (MAILP p, ADDRP addr)
  126. {
  127.     MAILP p1, p2;
  128.     int rettype;
  129.     long sztemp;
  130.     MDM_TRNS *m;                    /* MB 93-11-27 */
  131.  
  132.     p2 = find_mail (addr);
  133.  
  134.     if (p2 == NULL)
  135.     {
  136.         /* We didn't find it in what we have already */
  137.         p1 = p;
  138.         p1->mail_addr = *addr;
  139.         p1->oldest = (unsigned long) time (NULL);
  140.         rettype = 0;
  141.     }
  142.     else
  143.     {
  144.         /* We found it, so we have to make sure the higher level routine knows */
  145.         p1 = p2;
  146.         rettype = 1;
  147.     }
  148.  
  149. /*
  150.  * Get the size of the entry. If it's a FLO-type file,
  151.  * call netsize to find out how big the stuff contained in it
  152.  * actually is. If it's a packet, just take its size.
  153.  *
  154.  * Hold packets don't count.
  155.  */
  156.  
  157.     if (!no_size)
  158.     {
  159.         sztemp = 0L;
  160.  
  161.         if (!strncmp (&(dta_str.name[10]), "LO", 2))
  162.             p1->mailsize += (sztemp = netsize (p1));
  163.  
  164.         else if ((!strncmp (&(dta_str.name[10]), "UT", 2)) ||
  165.                 (!strncmp (&(dta_str.name[9]), "REQ", 3)))
  166.         {
  167.             struct tm tmstruc;
  168.             time_t curr_time;
  169.  
  170.             p1->numfiles++;
  171.             p1->mailsize += (sztemp = dta_str.size);
  172.  
  173.             curr_time = time (NULL);
  174.             tmstruc = *localtime (&curr_time);    /* Structure assignment */
  175.  
  176.             tmstruc.tm_year = (int) (dta_str.time >> 25) + 80;
  177.             tmstruc.tm_mon = (int) ((dta_str.time >> 21) & 0x0f) - 1;
  178.             tmstruc.tm_mday = (int) (dta_str.time >> 16) & 0x1f;
  179.  
  180.             tmstruc.tm_hour = (int) (dta_str.time >> 11) & 0x1f;
  181.             tmstruc.tm_min = (int) (dta_str.time >> 5) & 0x3f;
  182.             tmstruc.tm_sec = (int) dta_str.time & 0x1f;
  183.  
  184.             curr_time = mktime (&tmstruc);
  185.             p1->oldest = min ((unsigned long)curr_time, p1->oldest);
  186.         }
  187.  
  188.         if (dta_str.name[9] != 'H')
  189.             p1->callsize += sztemp;
  190.     }
  191.  
  192.     switch (dta_str.name[9])
  193.     {
  194.     case 'C':                    /* Crash */
  195.         p1->mailtypes |= MAIL_CRASH;
  196.         break;
  197.  
  198.     case 'H':                    /* Hold */
  199.         p1->mailtypes |= MAIL_HOLD;
  200.         break;
  201.  
  202.     case 'F':                    /* Normal */
  203.     case 'O':
  204.         p1->mailtypes |= MAIL_NORMAL;
  205.         break;
  206.  
  207.     case 'D':                    /* Direct */
  208.         p1->mailtypes |= MAIL_DIRECT;
  209.         break;
  210.  
  211.     case 'R':                    /* Request */
  212.         p1->mailtypes |= MAIL_REQUEST;
  213.         break;
  214.     }
  215.  
  216.     if (!nodefind (&(p1->mail_addr), 0))
  217.     {
  218.         p1->mailtypes |= MAIL_UNKNOWN;
  219.         return (rettype);
  220.     }
  221.  
  222.     /* Don't call for "HOLD" or "REQ" stuff. */
  223.  
  224.     if ((dta_str.name[9] == 'H') || (dta_str.name[9] == 'R'))
  225.     {
  226.         return (rettype);
  227.     }
  228.  
  229.     /* if modem type is undialable, don't call */    /* MB 93-11-27 */
  230.  
  231.     m = mm_head;
  232.     while (m != NULL)
  233.     {
  234.         if (m->mdm == newnodedes.ModemType)
  235.         {
  236.             if (!(*(m->pre) || *(m->suf)))
  237.                 return (rettype);
  238.             else
  239.                 break;
  240.         }
  241.         m = m->next;
  242.     }
  243.  
  244.     /* If there's no event, set mail to 'go' */
  245.  
  246.     if (cur_event < 0)
  247.     {
  248.         p1->mailtypes &= ~MAIL_QSMALL;
  249.         p1->mailtypes |= MAIL_WILLGO;
  250.         return (rettype);
  251.     }
  252.  
  253.     /* If it is a crash only event and we have crashmail, set it to go */
  254.  
  255.     if (e_ptrs[cur_event].behavior & MAT_HIPRICM)
  256.     {
  257.         if ((dta_str.name[9] == 'C') && (newnodedes.NodeFlags & B_CM))
  258.         {
  259.             p1->mailtypes &= ~MAIL_QSMALL;
  260.             p1->mailtypes |= MAIL_WILLGO;
  261.             return (rettype);
  262.         }
  263.     }
  264.  
  265.     /* If it is a crash only event and this wasn't crash, return */
  266.  
  267.     if ((dta_str.name[9] != 'C') && (e_ptrs[cur_event].behavior & MAT_CM))
  268.     {
  269.         return (rettype);
  270.     }
  271.  
  272.     /* Is this a local only event? */
  273.  
  274.     if (e_ptrs[cur_event].behavior & MAT_LOCAL)
  275.     {
  276.         /*
  277.          * If this is supposed to be only local, then get out if it isn't
  278.          */
  279.  
  280.         if (e_ptrs[cur_event].node_cost >= 0)
  281.         {
  282.             if ((int) newnodedes.RealCost > e_ptrs[cur_event].node_cost)
  283.             {
  284.                 return (rettype);
  285.             }
  286.         }
  287.         else
  288.         {
  289.             if ((int) newnodedes.RealCost < -(e_ptrs[cur_event].node_cost))
  290.             {
  291.                 return (rettype);
  292.             }
  293.         }
  294.     }
  295.  
  296.     /* Is this a non-mail window event? */
  297.  
  298.     if ((newnodelist || version7) &&
  299.         (!(e_ptrs[cur_event].behavior & MAT_NOMAIL24)))
  300.     {
  301.         /* If this guy can't handle crash, get out and try again */
  302.  
  303.         if (!(newnodedes.NodeFlags & B_CM))
  304.         {
  305.             return (rettype);
  306.         }
  307.     }
  308.  
  309.     /* Is this a receive only event? */
  310.  
  311.     if (e_ptrs[cur_event].behavior & MAT_NOOUT)
  312.     {
  313.         return (rettype);
  314.     }
  315.  
  316.     /* Is this a non-CM event? */
  317.  
  318.     if ((newnodelist || version7) &&
  319.         (e_ptrs[cur_event].behavior & MAT_NOCM) &&
  320.         (newnodedes.NodeFlags & B_CM))
  321.     {
  322.         return (rettype);
  323.     }
  324.  
  325.     /* See if we spent too much calling him already */
  326.  
  327.     if (bad_call (&(p1->mail_addr), 0))
  328.     {
  329.         p1->mailtypes |= MAIL_TOOBAD;
  330.         return (rettype);
  331.     }
  332.  
  333.     /* See if we have enough mail to send */
  334.  
  335.     if (!no_size && e_ptrs[cur_event].mailqsize > p1->callsize)
  336.     {
  337.         p1->mailtypes |= MAIL_QSMALL;
  338.         return (rettype);
  339.     }
  340.  
  341.     p1->mailtypes &= ~MAIL_QSMALL;
  342.     p1->mailtypes |= MAIL_WILLGO;
  343.  
  344.     return (rettype);
  345. }
  346.  
  347. static char LOCALFUNC 
  348. mail_stat (MAILP p)
  349. {
  350.     if (p->mailtypes & MAIL_UNKNOWN)
  351.         return ('!');
  352.     if (p->mailtypes & MAIL_TOOBAD)
  353.         return ('x');
  354.     if (p->mailtypes & MAIL_TRIED)
  355.         return ('#');
  356.     if (p->mailtypes & MAIL_WILLGO)
  357.         return ('*');
  358.     if (p->mailtypes & MAIL_QSMALL)
  359.         return ('<');
  360.     return ('-');
  361. }
  362.  
  363. char msc[10];
  364.  
  365. char *
  366. mail_status_chars (unsigned int p)
  367. {
  368.     char *q;
  369.  
  370.     q = msc;
  371.  
  372.     if (p & MAIL_CRASH)
  373.         *q++ = 'C';
  374.     if (p & MAIL_HOLD)
  375.         *q++ = 'H';
  376.     if (p & MAIL_DIRECT)
  377.         *q++ = 'D';
  378.     if (p & MAIL_NORMAL)
  379.         *q++ = 'N';
  380.     if (p & MAIL_REQUEST)
  381.         *q++ = 'R';
  382.     *q++ = '\0';
  383.  
  384.     return (msc);
  385. }
  386.  
  387. void 
  388. xmit_window (MAILP p1)
  389. {
  390.     MAILP p;
  391.     short i;
  392.     char j1[32];
  393.     char *jPtr;
  394.  
  395.     if (!fullscreen)
  396.         return;
  397.  
  398.     p = p1;
  399.  
  400.     sb_fillc (holdwin, ' ');
  401.     jPtr = j1;
  402.  
  403.     if (p == NULL)
  404.     {
  405.         sb_move (holdwin, 3, 5);
  406.         sb_puts (holdwin, MSG_TXT (M_NOTHING_IN_OUTBOUND));
  407.         return;
  408.     }
  409.  
  410.     strcpy (j1, MSG_TXT (M_OUTBOUND_HEADER));
  411.     sb_move (holdwin, 1, 2);
  412.     sb_puts (holdwin, jPtr);
  413.     for (i = 2; i < SB_ROW_HOLD; i++)
  414.     {
  415.         if (p == NULL)
  416.             break;
  417.  
  418.         do_xmit_line (j1, p);
  419.  
  420.         sb_move (holdwin, i, 2);
  421.         sb_puts (holdwin, jPtr);
  422.         p = p->next;
  423.     }
  424.     sb_show ();
  425. }
  426.  
  427. static void LOCALFUNC 
  428. do_xmit_line (char *line, MAILP p)
  429. {
  430.     ADDR addrT;
  431.  
  432.     if (no_size)
  433.     {
  434.         (void) sprintf (line, HoldNoSize,
  435.             Full_Addr_Str (&(p->mail_addr)),
  436.             mail_status_chars (p->mailtypes),
  437.             mail_stat (p));
  438.     }
  439.     else
  440.     {
  441.         addrT = p->mail_addr;
  442.         addrT.Domain = NULL;
  443.         (void) sprintf (line, HoldFmtStr,
  444.             Full_Addr_Str (&addrT),
  445.             (p->numfiles > 999 ? 999 : p->numfiles),
  446.             numdisp (p->mailsize),
  447.             mail_status_chars (p->mailtypes),
  448.             mail_stat (p));
  449.     }
  450. }
  451.  
  452. static void LOCALFUNC 
  453. xmit_sort ()
  454. {
  455.     MAILP p, p1, p2;
  456.  
  457.     p = mail_top;
  458.  
  459.     /* Find the first that is sendable */
  460.  
  461.     while (p != NULL)
  462.     {
  463.         if ((p->mailtypes & MAIL_WILLGO) &&
  464.             (!(p->mailtypes & MAIL_TOOBAD)) &&
  465.             (!(p->mailtypes & MAIL_UNKNOWN)))
  466.             break;
  467.         p = p->next;
  468.     }
  469.  
  470.     if (p == NULL)
  471.         return;
  472.  
  473.     /* Put the first sendable one on top */
  474.  
  475.     if (p != mail_top)
  476.     {
  477.         p->prev->next = p->next;
  478.         if (p->next != NULL)
  479.             p->next->prev = p->prev;
  480.         p->prev = NULL;
  481.         p->next = mail_top;
  482.         mail_top->prev = p;
  483.         mail_top = p;
  484.     }
  485.  
  486.     p1 = p;
  487.     p = p1->next;
  488.     while (p != NULL)
  489.     {
  490.         if ((p->mailtypes & MAIL_WILLGO) &&
  491.             (!(p->mailtypes & MAIL_TOOBAD)) &&
  492.             (!(p->mailtypes & MAIL_UNKNOWN)))
  493.         {
  494.             if (p->prev == p1)
  495.             {
  496.                 p1 = p;
  497.                 p = p->next;
  498.                 continue;
  499.             }
  500.             p2 = p->next;
  501.             p->prev->next = p->next;
  502.             if (p->next != NULL)
  503.                 p->next->prev = p->prev;
  504.             p->next = p1->next;
  505.             if (p1->next != NULL)
  506.                 p1->next->prev = p;
  507.             p->prev = p1;
  508.             p1->next = p;
  509.             p1 = p;
  510.             p = p2;
  511.         }
  512.         else
  513.         {
  514.             p = p->next;
  515.         }
  516.     }
  517. }
  518.  
  519. void 
  520. xmit_reset (int display)
  521. {
  522.     MAILP p;
  523.     int j, k, zone;
  524.     char *q, *s;
  525.     char *domain;
  526.     char *HoldName;
  527.     char pointspec[128];
  528.     ADDR tmp;
  529.     struct FILEINFO zone_dir =
  530.     {0};
  531.     struct FILEINFO pnt_dir =
  532.     {0};
  533.     long longzone;
  534.  
  535.     /* First get rid of all the old junk */
  536.  
  537.     p = mail_top;
  538.     if (p != NULL)
  539.     {
  540.         while (p->next != NULL)
  541.             p = p->next;
  542.         while (p->prev != NULL)
  543.         {
  544.             p = p->prev;
  545.             free (p->next);
  546.         }
  547.         if (p != NULL)
  548.             free (p);
  549.     }
  550.  
  551.     p = mail_top = NULL;
  552.  
  553. /*
  554.  * Initialize domain to scan. Choose (of course) the
  555.  * domain of our primary address.
  556.  *
  557.  * This domain is special in that its outbound is hold_area.
  558.  * All the other domains use their abbreviation as the name
  559.  * of their outbounds.
  560.  */
  561.  
  562.     k = 0;
  563.     domain = domain_name[0];
  564.     (void) strcpy (pointspec, hold_area);
  565.     q = &(pointspec[strlen (pointspec)]) - 1;
  566.     do
  567.     {
  568.  
  569. /*
  570.  * Initialize scan of zones in this domain. Using findfirst/findnext,
  571.  * get all the matching directories.
  572.  */
  573.         (void) strcpy (q, ".*");
  574.         j = 0;
  575.         while (!dfind (&zone_dir, pointspec, j))
  576.         {
  577.             j = 1;                /* Flip findfirst/findnext to findnext */
  578.  
  579. /*
  580.  * We have a match on the outbound spec. Make sure it's a directory.
  581.  *
  582.  * Then:
  583.  *
  584.  *       1) If no extension, we may only use it if this is alias 0
  585.  *       2) If an extension, it must be a 3-digit hex number
  586.  *
  587.  * If the extension passes one of these tests, get to work!
  588.  */
  589.             if (!(zone_dir.attr & FA_SUBDIR))
  590.                 continue;
  591.  
  592.             q = strchr (zone_dir.name, '.');
  593.             if (q == NULL)
  594.             {
  595.                 if (k != 0 && !no_zones)
  596.                     continue;
  597.                 zone = (int) alias[0].Zone;
  598.             }
  599.             else
  600.             {
  601.                 if (no_zones)
  602.                     continue;
  603.                 s = ++q;
  604.                 longzone = strtol (q, &q, 16);
  605.                 if ((s + 3) != q)
  606.                     continue;
  607.                 zone = (int) longzone;
  608. /*
  609.  * To avoid duplicating the primary scan,
  610.  * make sure that this isn't "domainname[0].zone[0]".
  611.  */
  612.                 if (!k && zone == (int) alias[0].Zone)
  613.                     continue;
  614.             }
  615. /*
  616.  * OK. We have a domain, an outbound directory, and a zone.
  617.  * That means there's an outbound to scan.
  618.  *
  619.  * Start by scanning the nodes.
  620.  */
  621.             tmp.Zone = zone;
  622.             tmp.Domain = domain;
  623.             tmp.Net = tmp.Node = tmp.Point = 0;
  624.             p = xmit_find (p, &tmp);
  625. /*
  626.  * Now we do the points contained in this outbound.
  627.  *
  628.  */
  629.             if (pvtnet <= 0)
  630.             {
  631.                 int f = 0;
  632.  
  633.                 HoldName = HoldAreaNameMunge (&tmp);
  634.                 (void) sprintf (pointspec, "%s*.PNT", HoldName);
  635.  
  636.                 while (!dfind (&pnt_dir, pointspec, f))
  637.                 {
  638.                     f = 1;
  639.                     if (sscanf (pnt_dir.name, "%04hx%04hx.", &(tmp.Net), &(tmp.Node)) != 2)
  640.                         continue;
  641.                     tmp.Point = 1;
  642.                     p = xmit_find (p, &tmp);
  643.                 }                /* got one */
  644.                 if (f)
  645.                     (void) dfind (&pnt_dir, NULL, 2);
  646.             }
  647.         }                        /* while !dfind (...) to get outbounds */
  648.         if (j)
  649.             (void) dfind (&zone_dir, NULL, 2);
  650. /*
  651.  * See if there are any more domains. If so, set up the right name
  652.  * for the outbound, so we can find 'em.
  653.  */
  654.         if ((domain = domain_name[++k]) != NULL)
  655.         {
  656.             *domain_loc = '\0';
  657.             (void) strcpy (pointspec, domain_area);
  658.             q = &(pointspec[strlen (pointspec)]);
  659.             s = domain_abbrev[k];
  660.             if (s != NULL)
  661.                 while (*s)
  662.                     *q++ = *s++;
  663.         }
  664.     }
  665.     while (domain != NULL);
  666.     next_mail = NULL;
  667.     xmit_sort ();
  668.     if (display)
  669.         xmit_window (mail_top);
  670.     next_rescan = (long) time (NULL) + 600L;    /* At least 10 min to next scan */
  671. }
  672.  
  673. static MAILP LOCALFUNC 
  674. xmit_find (MAILP p, ADDRP address)
  675. {
  676.     int j;
  677.     char next_one[127];
  678.     char *HoldName;
  679.     ADDR tmp;
  680.  
  681.     tmp = *address;
  682.  
  683.     HoldName = HoldAreaNameMunge (address);
  684.  
  685.     if (address->Point != 0)
  686.     {
  687.         (void) sprintf (next_one, "%s%04hx%04hx.PNT\\*.*",
  688.             HoldName, address->Net, address->Node);
  689.         tmp.Point = 0;
  690.     }
  691.     else
  692.     {
  693.         (void) sprintf (next_one, "%s*.*", HoldName);
  694.         tmp.Net = 0;
  695.         tmp.Node = 0;
  696.         tmp.Point = 0;
  697.     }
  698.  
  699.     j = 0;
  700.  
  701.     while (!dfind (&dta_str, next_one, j))
  702.     {
  703.         j = 1;
  704.  
  705.         /* We have a match. Was it a .FLO file or a .OUT file? */
  706.  
  707.         if (strncmp (&(dta_str.name[10]), "LO", 2) == 0)
  708.         {
  709.             /* FLO, DLO, CLO and HLO are the only ones! */
  710.  
  711.             if (strchr ("FDCH", dta_str.name[9]) == NULL)
  712.                 continue;
  713.         }
  714.         else if (strncmp (&(dta_str.name[10]), "UT", 2) == 0)
  715.         {
  716.             /* OUT, DUT, CUT and HUT are the only ones! */
  717.  
  718.             if (strchr ("ODCH", dta_str.name[9]) == NULL)
  719.                 continue;
  720.         }
  721.         else if (strncmp (&(dta_str.name[9]), "REQ", 3) != 0)
  722.             continue;
  723.  
  724.         /* We found a name, remember it */
  725.  
  726.         if (address->Point != 0)
  727.         {
  728.             if (sscanf (dta_str.name, "%08hx.", &(tmp.Point)) != 1)
  729.                 continue;
  730.         }
  731.         else if (sscanf (dta_str.name, "%04hx%04hx.", &(tmp.Net), &(tmp.Node)) != 2)
  732.             continue;
  733.  
  734.         if (p == NULL)
  735.         {
  736.             p = mail_top = (MAILP) calloc (sizeof (MAIL), 1);
  737.         }
  738.         else
  739.         {
  740.             p->next = (MAILP) calloc (sizeof (MAIL), 1);
  741.             p->next->prev = p;
  742.             p = p->next;
  743.         }
  744.  
  745.         if (xmit_install (p, &tmp))
  746.         {
  747.             /* No good */
  748.  
  749.             if (p->prev != NULL)
  750.             {
  751.                 p = p->prev;
  752.                 free (p->next);
  753.                 p->next = NULL;
  754.             }
  755.             else
  756.             {
  757.                 free (p);
  758.                 p = mail_top = NULL;
  759.             }
  760.         }
  761.  
  762.     }                            /* while (!done) */
  763.     if (j)
  764.         (void) dfind (&dta_str, NULL, 2);
  765.     return (p);
  766. }
  767.  
  768. int 
  769. xmit_next (ADDRP xaddr)
  770. {
  771.     int i, j;
  772.  
  773.     for (i = 0; i < 2; i++)
  774.     {
  775.         /* Set up the proper pointer */
  776.  
  777.         if ((next_mail == NULL) || (next_mail->next == NULL))
  778.         {
  779.             if (next_rescan < (long) time (NULL))
  780.                 xmit_reset (1);
  781.             next_mail = mail_top;
  782.         }
  783.         else
  784.         {
  785.             next_mail = next_mail->next;
  786.         }
  787.  
  788.         /* Loop through till we find something we can send */
  789.  
  790.         while (next_mail != NULL)
  791.         {
  792.             if ((next_mail->mailtypes & MAIL_WILLGO) &&
  793.                 (!(next_mail->mailtypes & MAIL_UNKNOWN)) &&
  794.                 (!(next_mail->mailtypes & MAIL_TOOBAD)))
  795.             {
  796.                 if (bad_call (&(next_mail->mail_addr), 0))
  797.                 {
  798.                     next_mail->mailtypes |= MAIL_TOOBAD;
  799.                 }
  800.                 else
  801.                 {
  802.                     /* If multitasking, check for mail before calling */
  803.  
  804.                     if ((TaskNumber != 0) && ((j = any_mail (next_mail)) <= 0))
  805.                     {
  806.                         if (j == 0)
  807.                             xmit_delete ();
  808.                         else
  809.                             next_mail = next_mail->next;
  810.                         continue;
  811.                     }
  812.                     *xaddr = next_mail->mail_addr;
  813.                     xmit_window (next_mail);
  814.                     return (1);
  815.                 }
  816.             }
  817.             next_mail = next_mail->next;
  818.         }
  819.     }
  820.  
  821.     /* Oh well, we tried */
  822.  
  823.     xmit_window (mail_top);
  824.     return (0);
  825. }
  826.  
  827. static void LOCALFUNC
  828. xmit_delete_one ()
  829. {
  830.     MAILP p;
  831.  
  832.     if (any_mail (next_mail) != 0)
  833.     {
  834.         status_line (MSG_TXT (M_STILL_HAVE_MAIL), Full_Addr_Str (&(next_mail->mail_addr)));
  835.  
  836.         /* We still have something for him */
  837.  
  838.         next_mail->mailtypes &= ~MAIL_WILLGO;
  839.         next_mail->mailtypes |= MAIL_TRIED;
  840.         return;
  841.     }
  842.  
  843.     if (next_mail != mail_top)
  844.     {
  845.         p = next_mail->next;
  846.         next_mail = next_mail->prev;
  847.         free (next_mail->next);
  848.         next_mail->next = p;
  849.         if (p != NULL)
  850.             p->prev = next_mail;
  851.     }
  852.     else
  853.     {
  854.         mail_top = mail_top->next;
  855.         free (next_mail);
  856.         if (mail_top != NULL)
  857.             mail_top->prev = NULL;
  858.         next_mail = NULL;
  859.     }
  860. }
  861.  
  862. void
  863. xmit_delete ()
  864. {
  865.     int i;
  866.  
  867.     if (next_mail == NULL && no_EMSI_Session)
  868.         return;
  869.  
  870.     if (no_EMSI_Session)
  871.     {
  872.         xmit_delete_one ();
  873.     }
  874.     else
  875.     {
  876.         for (i = (num_rakas - 1); i >= 0; i--)
  877.         {
  878.             next_mail = find_mail (&remote_akas[i]);
  879.             if (next_mail != NULL)
  880.                 xmit_delete_one ();
  881.         }
  882.     }
  883.  
  884.     xmit_window (mail_top);
  885.     no_EMSI_Session = TRUE;
  886.     num_rakas = 0;
  887. }
  888.  
  889. int 
  890. bad_call (ADDRP baddr, int rwd)
  891. {
  892.     int res;
  893.     int i, j;
  894.     struct FILEINFO bad_dta = {0};
  895.     FILE *bad_wazoo;
  896.     char *p;
  897.     char *HoldName;
  898.  
  899.     char fname[128];
  900.     char fname1[128];
  901.  
  902.     HoldName = HoldAreaNameMunge (baddr);
  903.     (void) sprintf (fname, "%s%s.$$?", HoldName, Hex_Addr_Str (baddr));
  904.     j = (int) strlen (fname) - 1;            /* Point at ?          */
  905.     res = -1;                                /* Initialize to fail  */
  906.  
  907.     i = 0;                                    /* This says findfirst */
  908.     while (!dfind (&bad_dta, fname, i))        /* as long as we match */
  909.     {
  910.         if (isdigit (bad_dta.name[11]))        /* is there a digit?   */
  911.         {
  912.             fname[j] = bad_dta.name[11];    /* Yes, copy to fname  */
  913.             res = fname[j] - '0';            /* Save it for testing */
  914.             break;                            /* Get out of while    */
  915.         }
  916.         else
  917.             i = 1;                            /* Else use findnext   */
  918.     }
  919.     if (i)
  920.         (void) dfind (&bad_dta, NULL, 2);
  921.  
  922.     if (res == -1)                            /* Successful search?  */
  923.     {
  924.         fname[j] = '0';                        /* No, base digit = 0  */
  925.     }
  926.  
  927.     if (rwd > 0)
  928.     {
  929.         /* Writing a bad call  */
  930.  
  931.         /* First create a filename that is one higher than what we've got */
  932.  
  933.         (void) strcpy (fname1, fname);
  934.         fname1[j]++;
  935.         if (fname1[j] > '9')
  936.             fname1[j] = '9';
  937.  
  938.         if (res == -1)                        /* Did we have a file? */
  939.         {                                    /* No, make one.       */
  940.             if (rwd == 2)                    /* No carrier */
  941.                 res = open (fname, O_CREAT | O_WRONLY | O_BINARY, S_IREAD | S_IWRITE);
  942.             else                            /* With carrier */
  943.                 res = open (fname1, O_CREAT | O_WRONLY | O_BINARY, S_IREAD | S_IWRITE);
  944.             i = rwd - 1;                    /* zero-based count    */
  945.             (void) write (res, (char *) &i, sizeof (int));
  946.             (void) close (res);                /* close the file      */
  947.         }
  948.         else
  949.         {                                    /* There was a file    */
  950.  
  951.             /*
  952.              * 2 = Unsuccessful, No carrier. Update contents of the file.
  953.              */
  954.  
  955.             if (rwd == 2)
  956.             {
  957.                 i = open (fname, O_RDONLY | O_BINARY);
  958.                 (void) read (i, (char *) &res, sizeof (int));
  959.                 (void) close (i);
  960.                 ++res;
  961.                 i = open (fname, O_CREAT | O_WRONLY | O_BINARY, S_IREAD | S_IWRITE);
  962.                 (void) write (i, (char *) &res, sizeof (int));
  963.                 (void) close (i);
  964.             }
  965.  
  966.             /*
  967.              * 1 = Unsuccessful, Carrier. Update file name to reflect the
  968.              * failure.
  969.              */
  970.  
  971.             else
  972.                 (void) rename (fname, fname1);
  973.         }
  974.     }
  975.     else if (rwd == 0)
  976.     {
  977.         /*
  978.          * 0 = We are reading a bad call status
  979.          */
  980.  
  981.         /* Is it automatically ok (no .$$ file there) ? */
  982.  
  983.         if (res == -1)
  984.             return (0);
  985.  
  986.         /* Were there too many connects with carrier? */
  987.  
  988.         if (res >= max_connects)
  989.             return (1);
  990.  
  991.         /* Ok, check for connects without carrier */
  992.  
  993.         res = 0;
  994.         i = open (fname, O_RDONLY | O_BINARY);
  995.         (void) read (i, (char *) &res, sizeof (int));
  996.         (void) close (i);
  997.         return (res >= max_noconnects);
  998.     }
  999.     else
  1000.     {
  1001.         /*
  1002.          * -1 = Cleanup of bad call status. This happens in two steps:
  1003.          * a) delete 'netnode.$$?' in hold area;
  1004.          * b) if a 'netnode.Z' file exists in hold area,
  1005.          *    1) delete all BADWAZOO.xxx files listed in the .Z file;
  1006.          *    2) delete the 'netnode.z' file.
  1007.          */
  1008.  
  1009.         if (res != -1)
  1010.             (void) unlink (fname);
  1011.  
  1012.         if (!mail_finished)
  1013.             return (0);
  1014.  
  1015.         (void) sprintf (fname, "%s%s.Z", HoldName, Hex_Addr_Str (baddr));
  1016.         if (dexists (fname))
  1017.         {
  1018.             if ((bad_wazoo = fopen (fname, read_ascii)) == NULL)
  1019.                 (void) got_error (MSG_TXT (M_OPEN_MSG), fname);
  1020.             else
  1021.             {
  1022.                 while (!feof (bad_wazoo))
  1023.                 {
  1024.                     e_input[0] = '\0';
  1025.                     if (!fgets (e_input, 64, bad_wazoo))
  1026.                         break;
  1027.  
  1028.                     /* Point to BADWAZOO.xxx */
  1029.  
  1030.                     p = strchr (e_input, ' ') + 1;
  1031.  
  1032.                     /* Then just past it and terminate */
  1033.  
  1034.                     p = strchr (p, ' ');
  1035.                     *p = '\0';
  1036.  
  1037.                     /* Back to where we were */
  1038.  
  1039.                     p = strchr (e_input, ' ') + 1;
  1040.  
  1041.                     /* Build file name and delete file */
  1042.  
  1043.                     (void) strcpy (fname1, CURRENT.sc_Inbound);
  1044.                     (void) strcat (fname1, p);
  1045.                     (void) unlink (fname1);
  1046.                 }
  1047.                 (void) fclose (bad_wazoo);
  1048.             }
  1049.             (void) unlink (fname);
  1050.         }
  1051.     }
  1052.     return (0);
  1053. }
  1054.  
  1055. void 
  1056. set_up_outbound ()
  1057. {
  1058.     MAILP mp;
  1059.  
  1060.     xmit_reset (1);
  1061.  
  1062.     /* and remember where we left off */
  1063.  
  1064.     if (hist.next_addr.Net != 0)
  1065.     {
  1066.         next_addr = hist.next_addr;
  1067.         next_addr.Domain = NULL;
  1068.         mp = find_mail (&next_addr);
  1069.         if ((mp == NULL) || (mp->prev == NULL))
  1070.         {
  1071.             next_mail = NULL;
  1072.             xmit_window (mail_top);
  1073.         }
  1074.         else
  1075.         {
  1076.             next_mail = mp->prev;
  1077.             xmit_window (next_mail);
  1078.         }
  1079.     }
  1080.     else
  1081.     {
  1082.         next_addr.Zone = 0;
  1083.         next_addr.Net = 0;
  1084.         next_addr.Node = 0;
  1085.         next_addr.Point = 0;
  1086.         next_addr.Domain = NULL;
  1087.         xmit_window (mail_top);
  1088.     }
  1089. }
  1090.  
  1091. void 
  1092. kill_bad (void)
  1093. {
  1094.     int j, k, zone;
  1095.     char *q, *s;
  1096.     char *domain;
  1097.     char *HoldName;
  1098.     char pointspec[255];
  1099.     ADDR tmp;
  1100.     struct FILEINFO zone_dir = {0};
  1101.     struct FILEINFO pnt_dir =  {0};
  1102.     long longzone;
  1103. /*
  1104.  * Initialize domain to scan. Choose (of course) the
  1105.  * domain of our primary address.
  1106.  *
  1107.  * This domain is special in that its outbound is hold_area.
  1108.  * All the other domains use their abbreviation as the name
  1109.  * of their outbounds.
  1110.  */
  1111.     k = 0;
  1112.     domain = domain_name[0];
  1113.     (void) strcpy (pointspec, hold_area);
  1114.     q = &(pointspec[strlen (pointspec)]) - 1;
  1115.     do
  1116.     {
  1117. /*
  1118.  * Initialize scan of zones in this domain. Using findfirst/findnext,
  1119.  * get all the matching directories.
  1120.  */
  1121.         (void) strcpy (q, ".*");
  1122.         j = 0;
  1123.         while (!dfind (&zone_dir, pointspec, j))
  1124.         {
  1125.             j = 1;                /* Flip findfirst/findnext to findnext */
  1126. /*
  1127.  * We have a match on the outbound spec. Make sure it's a directory.
  1128.  *
  1129.  * Then:
  1130.  *
  1131.  *       1) If no extension, we may only use it if this is alias 0
  1132.  *       2) If an extension, it must be a 3-digit hex number
  1133.  *
  1134.  * If the extension passes one of these tests, get to work!
  1135.  */
  1136.             if (!(zone_dir.attr & FA_SUBDIR))
  1137.                 continue;
  1138.  
  1139.             q = strchr (zone_dir.name, '.');
  1140.             if (q == NULL)
  1141.             {
  1142.                 if (k != 0 && !no_zones)
  1143.                     continue;
  1144.                 zone = (int) alias[0].Zone;
  1145.             }
  1146.             else
  1147.             {
  1148.                 if (no_zones)
  1149.                     continue;
  1150.                 s = ++q;
  1151.                 longzone = strtol (q, &q, 16);
  1152.                 if ((s + 3) != q)
  1153.                     continue;
  1154.                 zone = (int) longzone;
  1155. /*
  1156.  * To avoid duplicating the primary scan,
  1157.  * make sure that this isn't "domainname[0].zone[0]".
  1158.  */
  1159.                 if (!k && zone == (int) alias[0].Zone)
  1160.                     continue;
  1161.             }
  1162. /*
  1163.  * OK. We have a domain, an outbound directory, and a zone.
  1164.  * That means there's an outbound to scan.
  1165.  *
  1166.  * Start by scanning the nodes.
  1167.  */
  1168.             tmp.Zone = zone;
  1169.             tmp.Domain = domain;
  1170.             tmp.Net = tmp.Node = tmp.Point = 0;
  1171.             kill_one (&tmp);
  1172. /*
  1173.  * Now we do the points contained in this outbound.
  1174.  *
  1175.  */
  1176.             if (pvtnet <= 0)
  1177.             {
  1178.                 int f = 0;
  1179.  
  1180.                 HoldName = HoldAreaNameMunge (&tmp);
  1181.                 (void) sprintf (pointspec, "%s*.PNT", HoldName);
  1182.  
  1183.                 while (!dfind (&pnt_dir, pointspec, f))
  1184.                 {
  1185.                     f = 1;
  1186.                     if (sscanf (pnt_dir.name, "%04hx%04hx.", &(tmp.Net), &(tmp.Node)) != 2)
  1187.                         continue;
  1188.                     tmp.Point = 1;
  1189.                     kill_one (&tmp);
  1190.                 }                /* got one */
  1191.  
  1192.                 if (f)
  1193.                     (void) dfind (&pnt_dir, NULL, 2);
  1194.             }
  1195.         }                        /* while !dfind (...) to get outbounds */
  1196.         if (j)
  1197.             (void) dfind (&zone_dir, NULL, 2);
  1198. /*
  1199.  * See if there are any more domains. If so, set up the right name
  1200.  * for the outbound, so we can find 'em.
  1201.  */
  1202.         if ((domain = domain_name[++k]) != NULL)
  1203.         {
  1204.             *domain_loc = '\0';
  1205.             (void) strcpy (pointspec, domain_area);
  1206.             q = &(pointspec[strlen (pointspec)]);
  1207.             s = domain_abbrev[k];
  1208.             if (s != NULL)
  1209.                 while (*s)
  1210.                     *q++ = *s++;
  1211.         }
  1212.     }
  1213.     while (domain != NULL);
  1214. }
  1215.  
  1216. static void LOCALFUNC 
  1217. kill_one (ADDRP address)
  1218. {
  1219.     int j;
  1220.     char next_one[255];
  1221.     char thisfile[255];
  1222.     char *HoldName;
  1223.     char *p;
  1224.  
  1225.     HoldName = HoldAreaNameMunge (address);
  1226.  
  1227.     if (address->Point != 0)
  1228.     {
  1229.         (void) sprintf (next_one, "%s%04hx%04hx.PNT\\*.$$?",
  1230.             HoldName, address->Net, address->Node);
  1231.     }
  1232.     else
  1233.     {
  1234.         (void) sprintf (next_one, "%s*.$$?", HoldName);
  1235.     }
  1236.  
  1237.     j = 0;
  1238.     strcpy (thisfile, next_one);
  1239.     p = strrchr (thisfile, '*');
  1240.  
  1241.     while (!dfind (&dta_str, next_one, j))
  1242.     {
  1243.         j = 1;
  1244.  
  1245.         strcpy (p, dta_str.name);
  1246.         status_line (">Deleting %s", thisfile);
  1247.         unlink (thisfile);
  1248.  
  1249.     }                            /* while (!done) */
  1250.  
  1251.     if (j)
  1252.         (void) dfind (&dta_str, NULL, 2);
  1253. }
  1254.  
  1255. /*
  1256.  * Calculate size of mail queued for outbound.
  1257.  * Used to determine whether or not we have enough
  1258.  * mail to merit an outbound call.
  1259.  *
  1260.  * The original version of this code was donated by Henry Clark.
  1261.  */
  1262.  
  1263. static long LOCALFUNC 
  1264. netsize (MAILP p)
  1265. {
  1266.     struct stat stbuf;
  1267.     char net_path[127];
  1268.     char *ptr;
  1269.     FILE *temp;
  1270.     long accum = 0L;
  1271.     char *q;
  1272.  
  1273.     /* Append the ARCmail file name to the path line  */
  1274.  
  1275.     (void) sprintf (net_path, "%s%s.%s",
  1276.         HoldAreaNameMunge (&(p->mail_addr)),
  1277.         Hex_Addr_Str (&(p->mail_addr)),
  1278.         &dta_str.name[9]);
  1279.  
  1280.     temp = share_fopen (net_path, read_binary, DENY_NONE);
  1281.  
  1282.     if (temp == (FILE *) NULL)
  1283.         return (accum);
  1284.  
  1285.     while (!feof (temp))
  1286.     {
  1287. /*
  1288.  *      Make sure of a nice zero there if we're at an undetected EOF.
  1289.  *      Then try to read a line from the file.
  1290.  */
  1291.         net_path[0] = '\0';
  1292.         (void) fgets (net_path, 79, temp);
  1293. /*
  1294.  *      Clean up anything we don't want to see (blanks, tabs, CR, etc)
  1295.  */
  1296.         for (q = ptr = net_path; *q; q++)
  1297.             if (*q <= ' ')
  1298.                 *q = '\0';
  1299. /*
  1300.  *      File disposition commands should be skipped over to get to
  1301.  *      actual filenames.
  1302.  */
  1303.         if ((*ptr == TRUNC_AFTER) ||
  1304.             (*ptr == DELETE_AFTER) ||
  1305.             (*ptr == SHOW_DELETE_AFTER) ||
  1306.             (*ptr == NOTHING_AFTER))
  1307.             ptr++;
  1308. /*
  1309.  *      Now -- if what's left starts with a semicolon, it's a comment.
  1310.  *      If it starts with a tilde, the file has already been sent. If
  1311.  *      what we see is a zero, there's nothing on the line. In any one
  1312.  *      of these cases, we should skip this line.
  1313.  */
  1314.         if ((*ptr == '\0') ||
  1315.             (*ptr == ';') ||
  1316.             (*ptr == '~'))
  1317.             continue;
  1318. /*
  1319.  *      Get the file size by doing a stat call. If it's not there
  1320.  *      then we obviously need not add any size in. If the file is
  1321.  *        arcmail, figure it into the "oldest" calculation.
  1322.  */
  1323.         if (stat (ptr, &stbuf))    /* file exist? */
  1324.             continue;
  1325.         else
  1326.         {
  1327.             p->numfiles++;
  1328.             accum += stbuf.st_size;
  1329.             if (is_arcmail (ptr, 1 - strlen (ptr)))
  1330.                 p->oldest = min ((unsigned long)stbuf.st_ctime, p->oldest);
  1331.         }
  1332.     }
  1333.     (void) fclose (temp);
  1334.     return (accum);
  1335. }
  1336.  
  1337. /*
  1338.  * Figure out if there's any mail for the specified node.
  1339.  * Used to determine if we need to actually make a call.
  1340.  *
  1341.  * Returns 0 for no mail at all
  1342.  *         1 for non-hold mail
  1343.  *        -1 for hold mail only
  1344.  *
  1345.  * I can't remember who was the first to demand this. I've been
  1346.  * pummelled for a while and there's almost certainly been a loss
  1347.  * of grey matter.
  1348.  */
  1349.  
  1350. static int LOCALFUNC 
  1351. any_mail (MAILP node)
  1352. {
  1353.     struct FILEINFO dta = {0};
  1354.     char next_one[127];
  1355.     int ret = 0;
  1356.     int j = 0;
  1357.  
  1358.     (void) sprintf (next_one, "%s%s.*",
  1359.         HoldAreaNameMunge (&(node->mail_addr)),
  1360.         Hex_Addr_Str (&(node->mail_addr)));
  1361.  
  1362.     while (!dfind (&dta, next_one, j))
  1363.     {
  1364.         j = 1;
  1365.  
  1366. #ifndef JACK_DECKER
  1367.         if (dta.name[9] == 'H')
  1368.         {
  1369.             ret = -1;
  1370.             continue;
  1371.         }
  1372. #endif
  1373.         if ((!strncmp (&(dta.name[10]), "LO", 2)) ||
  1374.             (!strncmp (&(dta.name[10]), "UT", 2)))
  1375.         {
  1376.             ret = 1;
  1377.             break;
  1378.         }
  1379.     }
  1380.     if (j)
  1381.         (void) dfind (&dta, NULL, 2);
  1382.     return (ret);
  1383. }
  1384.  
  1385.